<?php
declare (strict_types=1);

namespace app\admin\service\base;

use app\BaseService;
use Firebase\JWT\BeforeValidException;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\JWT;
use Firebase\JWT\SignatureInvalidException;
use think\facade\Cache;

/**
 * 签发解析token服务层
 */
class JwtService extends BaseService
{
    /**
     * 加密解密key
     */
    const Token_Key = '36f17c3939ac3e7b2fc9396fa8e953ea';

    /**
     * 定义平台
     */
    const PlatformArr = [
        'admin',//总后台管理
        'datacenter',//数据中心管理
        'advertiser',//广告主管理
        'scan_bag',//扫码取袋
    ];

    /**
     * 生成缓存key
     * @param string $platform
     * @param int $userId
     * @return string
     */
    private static function generateKey(string $platform, int $userId): string
    {
        return 'access_token:' . $platform . '_' . $userId;
    }

    /**
     * 服务端签发Token
     * @param string $platform 平台
     * @param int $userId 用户id
     * @param int $expire 有效期
     * @return array
     */
    public static function authorizations(string $platform, int $userId, int $expire = 86400): array
    {
        //判断平台
        if (!in_array($platform, self::PlatformArr)) {
            return ['bool' => false, 'access_token' => ''];
        }
        //当前时间
        $time = time();
        //公用信息
        $token = [
            'iss' => '422wsdq.com', //签发者 可选
            'aud' => '422wsdq.com', //接收该JWT的一方，可选
            'iat' => $time, //签发时间
            'nbf' => $time, //某个时间点后才能访问，比如设置time+30，表示当前时间30秒后才能使用
            'scopes' => 'role_access', //token标识，请求接口的token
            'exp' => $time + $expire, //access_token过期时间
            'data' => [ //自定义信息，不要定义敏感信息
                'platform' => $platform,
                'userid' => $userId
            ],
        ];
        //生成token
        $access_token = JWT::encode($token, self::Token_Key);
        //缓存key
        $tKey = self::generateKey($platform, $userId);
        //用户最新的token写入缓存
        Cache::set($tKey, $access_token, $expire);
        //返回数据
        request()->access_token = $access_token;
        return ['bool' => true, 'access_token' => $access_token];
    }

    /**
     * 解析access_token
     * @param string $jwt
     * @return array
     */
    public static function vfAccessToken(string $jwt): array
    {
        request()->access_token = '';
        try {
            //解码jwt
            JWT::$leeway = 60;//当前时间减去60，把时间留点余地
            $decoded = JWT::decode($jwt, self::Token_Key, ['HS256']); //HS256方式，这里要和签发的时候对应
            $data = (array)$decoded;
            //获取自定义信息
            $platform = $data['data']->platform;
            $userid = $data['data']->userid;
            //token_exp有效期
            $exp = $data['exp'];
            //缓存key
            $tKey = self::generateKey($platform, $userid);
            //获取缓存
            $cache_token = Cache::get($tKey);
            //验证token的合法性
            if ($jwt !== $cache_token) {
                return ['bool' => false, 'data' => '非法签名,请重新登录!'];
            }
            //返回最新的access_token
            request()->access_token = $cache_token;
            //返回数据
            return ['bool' => true, 'data' => $userid, 'platform' => $platform];
        } catch (SignatureInvalidException $e) {
            //签名不正确
            return ['bool' => false, 'data' => '签名不正确,请重新登录!'];
        } catch (BeforeValidException $e) {
            //签名在某个时间点之后才能用
            return ['bool' => false, 'data' => $e->getMessage()];
        } catch (ExpiredException $e) {
            //token过期
            return ['bool' => false, 'data' => '签名过期,请重新登录!'];
        } catch (\Exception $e) {
            //其他错误
            return ['bool' => false, 'data' => '签名错误,请重新登录!'];
        }
    }

    /**
     * 通过用户id获取相对平台的token
     * @param string $platform
     * @param int $user_id
     * @return false|mixed
     */
    public static function getUserToken(string $platform, int $user_id): mixed
    {
        //缓存key
        $tKey = self::generateKey($platform, $user_id);
        //获取缓存
        $cache_token = Cache::get($tKey);
        request()->access_token = $cache_token;
        return $cache_token ?: false;
    }

    /**
     * 用户和管理员退出
     * @param int $user_id
     * @param string $platform
     * @return bool
     */
    public static function userAdminLogout(int $user_id, string $platform): bool
    {
        //缓存地址
        $tKey = self::generateKey($platform, $user_id);
        //删除缓存
        if (Cache::has($tKey)) {
            Cache::delete($tKey);
        }
        return true;
    }


}
